package main

import (
	"context"
	"fmt"
	"github.com/fsnotify/fsnotify"
	"github.com/gin-gonic/gin"
	"go-programming-tour-book/blog-service/global"
	"go-programming-tour-book/blog-service/internal/model"
	"go-programming-tour-book/blog-service/internal/routers"
	"go-programming-tour-book/blog-service/pkg/logger"
	"go-programming-tour-book/blog-service/pkg/setting"
	"go-programming-tour-book/blog-service/pkg/tracer"
	"gopkg.in/natefinch/lumberjack.v2"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func init() {
	err := setupSetting()

	if err != nil {
		log.Fatalf("yaml config load is fail:%v", err)
	}

	err = setupDBEngine()

	if err != nil {
		log.Fatalf("db config load is fail:%v", err)
	}

	err = setupLogger()

	if err != nil {
		log.Fatalf("log config load is fail")
	}

	err = setupTracer()

	if err != nil {
		log.Fatalf("tracer load is fail")
	}
}

/**
@title 博客系统1.0
@version 1.0
@description GO语言gin框架博客练手项目
*/
func main() {
	gin.SetMode(global.ServerSetting.RunMode)

	router := routers.NewRouter()

	s := &http.Server{
		Addr:           ":" + global.ServerSetting.HttpPort,
		Handler:        router,
		ReadTimeout:    global.ServerSetting.ReadTimeout,
		WriteTimeout:   global.ServerSetting.WriteTimeout,
		MaxHeaderBytes: 1 << 20,
	}

	go func() {
		err := s.ListenAndServe()

		if err != nil && err != http.ErrServerClosed {
			log.Fatalf("s.ListenAndServer er :%v", err)
		}
	}()

	//等待中断信号
	quit := make(chan os.Signal)

	//接受syscall.SIGINT和syscall.SIGTERM信号
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

	<-quit

	log.Println("Shuting down server")

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)

	defer cancel()

	if err := s.Shutdown(ctx); err != nil {
		log.Fatalf("Server forced to shutdown:", err)
	}

	log.Println("Server exiting")
}

//加载配置文件
func setupSetting() error {
	setting, err := setting.NewSetting()

	if err != nil {
		return err
	}

	err = setting.ReadSection("Server", &global.ServerSetting)

	if err != nil {
		return err
	}

	err = setting.ReadSection("App", &global.AppSetting)

	if err != nil {
		return err
	}

	err = setting.ReadSection("Database", &global.DatabaseSetting)

	if err != nil {
		return err
	}

	err = setting.ReadSection("JWT", &global.JWTSetting)

	if err != nil {
		return err
	}

	err = setting.ReadSection("Email", &global.EmailSetting)

	if err != nil {
		return err
	}

	global.JWTSetting.Expire *= time.Second
	global.ServerSetting.ReadTimeout *= time.Second
	global.ServerSetting.WriteTimeout *= time.Second

	return nil
}

//数据库初始化
func setupDBEngine() error {
	var err error

	global.DBEngine, err = model.NewDBEngine(global.DatabaseSetting)

	if err != nil {
		return err
	}

	return nil
}

//日志初始化
func setupLogger() error {
	fileName := global.AppSetting.LogSavePath + "/" + global.AppSetting.LogFileName + global.AppSetting.LogFileExt

	global.Logger = logger.NewLogger(&lumberjack.Logger{
		Filename:  fileName,
		MaxSize:   600,
		MaxAge:    30,
		LocalTime: true,
	}, "", log.LstdFlags).WithCaller(2)

	return nil
}

//链路追踪初始化
func setupTracer() error {
	jaegerTracer, _, err := tracer.NewJaegerTracer(
		"blog-service",
		"127.0.0.1:6831",
	)

	if err != nil {
		return err
	}

	global.Tracer = jaegerTracer

	return nil
}

//监听配置文件热更新
func watchConfig() {
	watcher, _ := fsnotify.NewWatcher()

	defer watcher.Close()

	done := make(chan bool)

	go func() {
		for {
			select {
			case event, ok := <-watcher.Events:
				if !ok {
					return
				}

				fmt.Println("event:", event)

				if event.Op&fsnotify.Write == fsnotify.Write {
					fmt.Println("modified file:", event.Name)
				}
			case err, ok := <-watcher.Errors:
				if !ok {
					return
				}

				fmt.Println("error:", err)
			}
		}
	}()

	path := "E:/go-work/src/go-programming-tour-book/blog-service/configs"

	_ = watcher.Add(path)

	<-done
}
